#ifndef NODE_H
#define NODE_H

#include <QVector>
#include <QSharedPointer>
#include <QMap>
#include <QDebug>
#include <gsl/gsl_randist.h>
#include <limits>
#include <math.h>
#include <assert.h>
#include "nodestats.h"

#define MIN_P std::numeric_limits<double>::min() //0.00000000000000000000000000001
#define VALID_LOG(x) log((x < MIN_P) ? MIN_P : x)
#define VALID_INV_LOG(x) (x == 0.0) ? -std::numeric_limits<double>::max() : (log(1.0) - VALID_LOG(x))

enum NodeType
{
    NORMAL,
    GAMMA,
    INVERSE_GAMME,
    POISSON,
    BETA,
    BERNOULLI,
    BINOMIAL
};

class Node
{
protected:

    NodeType nodeType;    
    gsl_rng* randomNumberGenerator;

    QString label;

    bool   isMultiNode;
    bool   isObserved;
    bool   useCandidate;
    double value;
    double candidateValue;

    double candSd;        

    QVector<Node * > * parents;
    QVector<Node * > * children;   

    virtual double generateSampleFromDistribution();
    virtual bool inRange(double v);

public:        

    bool isNecessary;

    NodeStats * stats;

    Node(double v);
    Node(QString label, double v, double sds, bool isObserved = false);
    ~Node();

    QString getLabel();
    virtual double getValue();
    double getCandSd();
    bool   getIsObservation();

    int addParentNode(Node * node);
    virtual void addChildNode(Node * node);
    QVector<Node * > * getParentNodes();
    QVector<Node * > * getChildNodes();

    QVector<Node * > getExplicitParentNodes();

    QVector<double> * generateSamples(int N);

    void setObserved(bool val);

    virtual double generateSample();
    virtual double computeCompleteConditional();

    virtual double computeLogLikelihood()
    {
        assert(false);

        return 0.0;
    }

    static QString generateId()
    {
        static int id = 0;
        return QString::number(id++);
    }
};

#endif // NODE_H
